package org.zxp.thread.ccontainer;

import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @program: zxp-thread-test
 * @description: CopyOnWriteArrayList测试
 * @author: X-Pacific zhang
 * @create: 2019-05-26 17:27
 **/
public class CopyOnWriteArrayListTest {
    public static void main(String[] args) throws InterruptedException {
        List<Integer> arr = new CopyOnWriteArrayList<>();
//        List<Integer> arr = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            arr.add(i);
        }
        //多线程读
        for (int i = 0; i < 1000; i++) {
            final int m = i;
            new Thread(() -> {
                try {Thread.sleep(1);} catch (InterruptedException e) {}//等等下面读线程开始
                Iterator<Integer> iterator = arr.iterator();
                try {Thread.sleep(new Random().nextInt(10));} catch (InterruptedException e) {}//造成不一致的可能性
                int count = 0;
                while(iterator.hasNext()){
                    //如果是ArrayList，这个点会报错，iterator映射到原有数组，因为checkForComodification会发现modCount（原始arrayList）与expectedModCount不一致了(快速失败)
                    //CopyOnWriteArrayList 调用iterator时生成的是一个新的数组快照，遍历时读取的是快照，所以永远不会报错（即使读取后修改了列表）
                    //CopyOnWriteArrayList修如果不拷贝新的数组（加锁仍保证其线程安全）直接修改原来的数据结构(不是原子的)，那么在读的时候就要加锁了，如果读不加锁就有可能读到修改数组的“半成品”（有可能COWIterator<E>(getArray(), 0);就是个半成品）
                    //而拷贝了新的数组，即使修改没有完成，遍历是拿到的也是老的数组，所以不会有问题。
                    iterator.next();
                    count++;
                }
                System.out.println("read:"+count);
            }).start();

        }

        //多线程写
        for (int ii = 0; ii < 10; ii++) {
            new Thread(() -> {
                arr.add(123);
                System.out.println("write");
            }).start();
        }
    }
}
